using Clancy.Interfaces;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reactive;
using System.Reactive.Linq;

namespace Clancy.Ui.ViewModels
{
    public abstract class ClancyEditorViewModelBase : RibbonElementProvidingViewModelBase
    {
        private readonly List<IDisposable> m_OperationAdapterDisposables = new List<IDisposable>();

        private readonly IOperationalAdapterProvider m_OperationalAdapterProvider;
        private readonly ISurveilanceStorage m_SurveilanceStorage;

        protected ClancyEditorViewModelBase(IOperationalAdapterProvider operationalAdapterProvider, ISurveilanceStorage surveilanceStorage)
        {
            m_SurveilanceStorage = surveilanceStorage;
            m_OperationalAdapterProvider = operationalAdapterProvider;
            AttachToOperationModeChange();
        }

        public IObservable<OperationMode> CurrentOperationMode
        {
            get { return m_OperationalAdapterProvider.OperationMode; }
        }

        public IOperationAdapter OperationAdapter
        {
            get { return m_OperationalAdapterProvider.OperationAdapter; }
        }

        public ISurveilanceStorage SurveilanceStorage
        {
            get { return m_SurveilanceStorage; }
        }

        protected void AttachToCollection(object collection, Action<object> addAction, Action<object> removeAction)
        {
            IObservable<EventPattern<NotifyCollectionChangedEventArgs>> collectionChangedObservable =
                Observable.FromEventPattern<NotifyCollectionChangedEventArgs>(collection, "CollectionChanged");

            m_OperationAdapterDisposables.Add(collectionChangedObservable
                .Where(change => change.EventArgs.Action == NotifyCollectionChangedAction.Add)
                .Select(change => change.EventArgs.NewItems)
                .ObserveOnDispatcher()
                .Subscribe(addAction));

            m_OperationAdapterDisposables.Add(collectionChangedObservable
                .Where(change => change.EventArgs.Action == NotifyCollectionChangedAction.Remove)
                .Select(change => change.EventArgs.OldItems)
                .ObserveOnDispatcher()
                .Subscribe(removeAction));
        }

        protected override void DisposeElements()
        {
            DisposeMultipleElements(m_OperationAdapterDisposables);
        }

        protected virtual void RefreshOperationsAdapter()
        {
            DisposeMultipleElements(m_OperationAdapterDisposables);
        }

        private void AttachToOperationModeChange()
        {
            if (m_OperationalAdapterProvider == null)
                return;

            m_OperationalAdapterProvider.OperationMode.Subscribe(_ => RefreshOperationsAdapter());
        }
    }
}